home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
getmat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
20KB
|
829 lines
/*
* $Id: getmat.c,v 0.91 1994/02/20 00:53:11 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Low level supporting routines.
*
* WARNING:
* these are NOT general purposes stuff and all matrix routines have the
* following assumptions:
* 1. sizeof(char *)==sizeof(int *)==sizeof(long **)==sizeof(char **)
* 2. short alignment
*/
#if !defined(lint) && defined(F_ID)
char *id_mat = "$Id: getmat.c,v 0.91 1994/02/20 00:53:11 zhao Pre-Release $";
#endif
#include <stdio.h>
#include <string.h>
#include "utype.h"
#include "ulib.h"
#include "uproto.h"
#include "dmalloc.h"
static int usecalloc; /* use calloc instead of malloc if set */
void
set_use_calloc(int y)
{
usecalloc = y;
}
/***************************************************************
* make_mat will take a block of memory and assign the pointers
* so that we can use it as a matrix
***************************************************************/
void
make_mat(void *mat, void *mem, int nrow, int ncol, size_t esize)
{
int i, j;
char **m = mat;
m[0] = mem;
j = ncol * esize;
for (i = 1; i < nrow; i++)
m[i] = m[i - 1] + j;
}
#ifndef M_DBG
/*
* if M_DBG is set, get_mat will be replaced by another function which
* will remember where it is called
*/
/*********************************************************************
* get a matrix of nrow * ncol with element size of esize bytes.
*********************************************************************/
void *
get_mat(int nrow, int ncol, size_t esize)
{
register char **m;
void *p;
if (nrow < 1 || ncol < 1)
{
M_err("Getmatrix", "Bad parameters c=%d r=%d", ncol, nrow);
return 0;
}
if (!(m = malloc(sizeof(void *) * nrow)))
{
M_err("Getmatrix", "GetMatrix: malloc failure");
return 0;
}
if (!(p = usecalloc ? calloc(nrow * ncol, esize) :
malloc(esize * nrow * ncol)))
{
M_err("Getmatrix", "GetMatrix: malloc failure");
return 0;
}
/* make the matrix */
make_mat(m, p, nrow, ncol, esize);
return m;
}
#else /* ! M_DBG */
/*******************************************************************
* Debug version of get_mat: f and line are the file and line number
* where get_mat is called
*******************************************************************/
void *
dbg_getmat(int nrow, int ncol, size_t esize, const char *f, int line)
{
register char **m;
char ff[1024];
void *p;
if (nrow < 1 || ncol < 1)
{
M_err("Getmatrix", "Bad parameters c=%d r=%d", ncol, nrow);
return 0;
}
/* construct a complete name */
strcpy(ff, "getmat_");
strncat(ff, f, sizeof(ff) - 10);
m = dbg_malloc(sizeof(void *) * nrow, ff, line);
p = usecalloc ? dbg_calloc(nrow * ncol, esize, ff, line) :
dbg_malloc(esize * nrow * ncol, ff, line);
if (!m || !p)
{
if (m)
free(m);
if (p)
free(p);
M_err("Getmatrix", "GetMatrix: malloc failure");
return 0;
}
/* make the matrix */
make_mat(m, p, nrow, ncol, esize);
return m;
}
#endif
/*************************************************************
* free a matrix allocated by Getmatrix
**************************************************************/
void
free_mat(void *p)
{
char **m = p;
if (p && m[0])
{
free(m[0]);
m[0] = 0;
free(p);
}
}
/*************************************************************
* get a three-d tensor T[d1][d2][d3]
*************************************************************/
void *
get_3d(int d1, int d2, int d3, size_t es)
{
char **m;
int i;
/*
* we got one more, then the freeing routine will have easier time figure
* out the leading dimension
*/
m = malloc(sizeof(void *) * (d1 + 1));
for (i = 0; i < d1; i++)
m[i] = get_mat(d2, d3, es);
m[d1] = 0;
return m;
}
/******** free the tensor gotten by get_3d ********/
void
free_3d(void *p)
{
char **m = p;
if (p && m[0])
{
while (*m)
{
free_mat(*m);
*m = 0;
m++;
}
}
}
/****************************************************************
* Pack a R,G,B into a RGBA. Special provisions are made for
* grayscale images, signified by r==g
***************************************************************/
void
pack_mat(register rgba_t *m, register pc_t *r, register pc_t *g,
register pc_t *b, long total)
{
register pc_t *rend;
if (r != g)
{
for (rend = r + total; r < rend; r++, g++, b++, m++)
*m = Pack(*r, *g, *b);
}
else
{
for (rend = r + total; r < rend; r++, m++)
*m = Pack(*r, *r, *r);
}
}
/* unpack */
void
unpack_mat(register rgba_t *m,
register pc_t *r, register pc_t *g, register pc_t *b,
long total)
{
register pc_t *rend;
if (r != g)
{
for (rend = r + total; r < rend; r++, g++, b++, m++)
Unpack(*m, *r, *g, *b);
}
else
{
for (rend = r + total; r < rend; r++, m++)
*r = get_R(*m);
}
}
/*****************************************************************
* Initialize a submatrix to m0
*****************************************************************/
void
init_mat(void *m, int rows, int cols, size_t esize, unsigned long m0)
{
if (esize == sizeof(rgba_t))
{
register rgba_t *p = ((rgba_t **) m)[0], *ps = p + rows * cols;
while (--ps >= p)
*ps = m0;
}
else
{
register ci_t *p = ((ci_t **) m)[0], *ps = p + rows * cols;
while (--ps >= p)
*ps = m0;
}
}
/*****************************************************************
* given a matrix, get a submatrix out of it. r,c are the original
* matrix order and rr,cc are the submatrix order r1 and c1 are
* the starting posisiton. Should never be called directly by any
* routine other than subimage routines.
****************************************************************/
/* ARGSUSED */
void *
get_submat(void *in, int r, int c,
int r1, int c1, int rr, int cc, size_t esize)
{
register int r2 = r1 + rr - 1;
register int i, err, off = esize * c1;
register size_t size = esize * cc;
register char **nm, **om = in;
#ifdef CHECK_MAT
if (rr > r || cc > cc || r1 < 0 || c1 < 0)
{
M_warn("GetSubMat", "Bad function parameters");
return 0;
}
#endif
if (!(nm = get_mat(rr, cc, esize)))
return 0;
for (i = r1, err = 0; i <= r2 && !err; i++)
err = memcpy(nm[i - r1], om[i] + off, size) == 0;
if (err)
{
free_mat(nm);
nm = 0;
}
return nm;
}
/**********************************************************************
* Things to do when putting back a submatrix.
* Note that there is no way we can do meaningful things except Masking
* with CI images and therefore, when esize == 2, ignore matop request
****************************************************************/
static Matop_t matop = O_NONE; /* current op mode */
static rgba_t magicpix; /* masking magic pixel */
/**** set the operations to do when putting a submatrix back ***/
void
set_mat_op(Matop_t m)
{
matop = m;
}
/******* get current settings ******/
Matop_t
get_mat_op(void)
{
return matop;
}
/*****************************************************************
* What the masking "magic" pixel is. Default is black.
* Keep RGB only. This is sort of broken as theoretically
* there is no "free" pixel for the magic pixel. Alpha
* channel is the best for these kind of things.
****************************************************************/
void
set_magic_pix(rgba_t m)
{
magicpix = m & 0x00ffffff;
}
/***** get current magic pixel ****/
rgba_t
get_magic_pix(void)
{
return magicpix;
}
/**********************************************************
* replace part of a matrix with a new matrix, after performing
* defined operations: Add, sub, mask etc
***********************************************************/
static void
mask_submat(char **dest, char **src, int nr, int nc,
int off, size_t esize)
{
register int r;
if (esize == sizeof(rgba_t))
{
register rgba_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (rgba_t *) src[r];
ras = (rgba_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras = ((*ss & 0x00ffffff) != magicpix ? *ss : *ras);
}
}
else
{
register ci_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (ci_t *) src[r];
ras = (ci_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras = (*ss != magicpix ? *ss : *ras);
}
}
}
static void
add_submat(char **dest, char **src, int nr, int nc,
int off, size_t esize)
{
register int r;
if (esize == sizeof(rgba_t))
{
register rgba_t *ras, *rase, *ss;
int pc1[3], pc2[3];
for (r = 0; r < nr; r++)
{
ss = (rgba_t *) src[r];
ras = (rgba_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
{
Unpack(*ras, pc1[0], pc1[1], pc1[2]);
Unpack(*ss, pc2[0], pc2[1], pc2[2]);
if ((pc1[0] += pc2[0]) > PCMAXV)
pc1[0] = PCMAXV;
if ((pc1[1] += pc2[1]) > PCMAXV)
pc1[1] = PCMAXV;
if ((pc1[2] += pc2[2]) > PCMAXV)
pc1[2] = PCMAXV;
*ras = Pack(pc1[0], pc1[1], pc1[2]);
}
}
}
else
{
register ci_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (ci_t *) src[r];
ras = (ci_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras = *ss;
}
}
}
static void
sub_submat(char **dest, char **src, int nr, int nc,
int off, size_t esize)
{
int r;
if (esize == sizeof(rgba_t))
{
register rgba_t *ras, *rase, *ss;
int pc1[3], pc2[3];
for (r = 0; r < nr; r++)
{
ss = (rgba_t *) src[r];
ras = (rgba_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
{
Unpack(*ras, pc1[0], pc1[1], pc1[2]);
Unpack(*ss, pc2[0], pc2[1], pc2[2]);
if ((pc1[0] -= pc2[0]) < 0)
pc1[0] = 0;
if ((pc1[1] -= pc2[1]) < 0)
pc1[1] = 0;
if ((pc1[2] -= pc2[2]) < 0)
pc1[2] = 0;
*ras = Pack(pc1[0], pc1[1], pc1[2]);
}
}
}
else
{
register ci_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (ci_t *) src[r];
ras = (ci_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras = *ss;
}
}
}
static void
diff_submat(char **dest, char **src, int nr, int nc,
int off, size_t esize)
{
register int r;
if (esize == sizeof(rgba_t))
{
register rgba_t *ras, *rase, *ss;
int pc1[3], pc2[3];
for (r = 0; r < nr; r++)
{
ss = (rgba_t *) src[r];
ras = (rgba_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
{
Unpack(*ras, pc1[0], pc1[1], pc1[2]);
Unpack(*ss, pc2[0], pc2[1], pc2[2]);
if ((pc1[0] -= pc2[0]) < 0)
pc1[0] = -pc1[0];
if ((pc1[1] -= pc2[1]) < 0)
pc1[1] = -pc1[1];
if ((pc1[2] -= pc2[2]) < 0)
pc1[2] = pc1[2];
*ras = Pack(pc1[0], pc1[1], pc1[2]);
}
}
}
else
{
register ci_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (ci_t *) src[r];
ras = (ci_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras = *ss;
}
}
}
static void
xor_submat(char **dest, char **src, int nr, int nc,
int off, size_t esize)
{
int r;
if (esize == sizeof(rgba_t))
{
register rgba_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (rgba_t *) src[r];
ras = (rgba_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras ^= *ss;
}
}
else
{
register ci_t *ras, *rase, *ss;
for (r = 0; r < nr; r++)
{
ss = (ci_t *) src[r];
ras = (ci_t *) (dest[r] + off);
for (rase = ras + nc; ras < rase; ras++, ss++)
*ras ^= *ss;
}
}
}
/*****************************************************************
* Insert a (smaller) matrix new into another (larger) matrix old
*
****************************************************************/
/* ARGSUSED */
int
put_submat(void *old, int orow, int ocol,
void *new, int r1, int c1, int rr, int cc,
size_t esize)
{
int r2 = r1 + rr - 1;
register int err = 0, r, off = esize * c1;
register char **dest = old, **src = new;
register size_t size = esize * cc;
#ifdef CHECK_MAT
if (r1 < 0 || c1 < 0 || r2 >= orow || (cc + c1 - 1) >= ocol)
{
M_warn("PutSubMat", "Bad input");
return -1;
}
#endif
/*
* if no operation or matrix is color index, simple put the matrix back,
* i.e., overwrite
*/
switch (matop)
{
case O_MASK:
mask_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
break;
case O_ADD:
add_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
break;
case O_SUB:
sub_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
break;
case O_DIFF:
diff_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
break;
case O_XOR:
xor_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
break;
default:
for (r = r1; r <= r2 && !err; r++)
err = memcpy(dest[r] + off, src[r - r1], size) == 0;
break;
}
return err ? -1 : 0;
}
/**************************************************************
* fill a submatrix with a particular val
**************************************************************/
#define Fill_submat(type, fill) \
do { \
register type **mat = m; \
for ( r = r1; r <= r2; r++) \
for ( c = c1; c <= c2; c++) \
mat[r][c] = fill; \
} while (ZERO)
void
fill_submat(void *m, int r1, int r2, int c1, int c2, rgba_t f, size_t e)
{
register ci_t cfill = (ci_t) f;
register int r, c;
#ifdef CHECK_MAT
if (r1 < 0 || c1 < 0)
{
M_warn("FillSubMat", "Bad input");
return;
}
#endif
if (e == sizeof(rgba_t))
Fill_submat(rgba_t, f);
else if (e == sizeof(ci_t))
Fill_submat(ci_t, cfill);
}
/*****************************************************
* flip a matrix (mirror operations)
****************************************************/
#define flip_col(type) \
do { \
register type **mm = m, *t, *h, tmp; int j; \
for (j = 0; j < r; j++) \
for (t = (h = mm[j]) + (c - 1); t > h; t--, h++) { \
tmp = *h; *h = *t; *t = tmp; \
} \
} while(ZERO)
int
flip_mat(void *m, int r, int c, int f, size_t e)
{
#ifdef CHECK_MAT
if (!m || (e != sizeof(ci_t) && e != sizeof(rgba_t)))
{
M_warn("FlipMat", "Bad matrix");
return -1;
}
#endif
switch (f)
{
case 'r': /* flip rows */
case 'y':
{
register int i, is = (r / 2);
register size_t size = e * c;
register char *tmp, **mm = m;
if (!(tmp = malloc(size)))
return -1;
for (i = 0; i < is; i++)
{
(void) memcpy(tmp, mm[i], size);
(void) memcpy(mm[i], mm[r - 1 - i], size);
(void) memcpy(mm[r - 1 - i], tmp, size);
}
free(tmp);
}
break;
case 'c':
case 'x': /* flip colums */
if (e == sizeof(ci_t))
{
flip_col(ci_t);
}
else
{
flip_col(rgba_t);
}
break;
default: /* error */
M_err("FlipMat", "Bad request");
return -1;
}
return 0;
}
static int
check_funcp(void *m, int nr, int nc, size_t e, const char *f)
{
if (!m)
{
M_warn(f, "Bad input matrix");
return -1;
}
if (nr < 1 || nc < 1)
{
M_warn(f, "Bad matrix dimension: nr=%d nc=%d", nr, nc);
}
if (e != sizeof(ci_t) && e != sizeof(rgba_t))
{
M_warn(f, "Bad input matrix element size %d", e);
return -1;
}
return 0;
}
/***************************************************************
* rotate a matrix by 90, or -90 or multiples of it
* Rotate 180 can be implented as two 90 rotations, but current
* code is faster.
*
* NOTE: input dimension is the diemsnion of the matrix to be
* rotated. caller must take care of the rotated dimensions
**************************************************************/
/*
* Rotate 90 degrees
*/
#define DO_90(type) \
do { \
register type *p= ((type **)mm)[0], **oo= m; \
register int i, j; \
for ( j= 0; j < col; j++) { \
for (i= row-1; i>=0; i--) *p++ = oo[i][j]; \
} \
} while (ZERO)
/*
* Rotate -90 degrees
*/
#define DO_M90(type) \
do { \
register type *p= ((type **) mm)[0], **o= m; \
register int i, j; \
for (j= col - 1; j >= 0; j--) { \
for (i= 0; i < row; i++) *p++ = o[i][j]; \
} \
} while (ZERO)
#define DO_180(ty) \
do { \
register ty *p= ((ty **)mm)[0], *o=((ty **)m)[0];\
register ty *os; \
for (os= o + col*row-1 ; os>o; *p++ = *os--) ; \
} while(ZERO)
void *
rotate_mat(void *m, int row, int col, int deg, size_t e)
{
void *mm;
int nrow, ncol;
if (check_funcp(m, row, col, e, "Rotate:"))
return 0;
if (deg == 90 || deg == -90)
{
nrow = col;
ncol = row;
}
else
{
nrow = row;
ncol = col;
}
if (!(mm = get_mat(nrow, ncol, e)))
return 0;
if (deg == 90)
{
if (e == sizeof(rgba_t))
{
DO_90(rgba_t);
}
else
{
DO_90(ci_t);
}
}
else if (deg == -90)
{
if (e == sizeof(rgba_t))
{
DO_M90(rgba_t);
}
else
{
DO_M90(ci_t);
}
}
else if (deg == 180 || deg == -180)
{
if (e == sizeof(rgba_t))
{
DO_180(rgba_t);
}
else
{
DO_180(ci_t);
}
}
else
{
M_warn("RotMat", "Bad angle %d", deg);
}
return mm;
}